package org.codefilarete.stalactite.sql.statement.binder;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * A contract for a {@link ParameterBinder} index.
 * The difference with {@link ParameterBinderProvider} is that an index can be queried for its whole keys and content,
 * hence permitting optimization for "massive" operation such as iterating all over the {@link ParameterBinder}.
 * 
 * @author Guillaume Mary
 */
public interface ParameterBinderIndex<K, BINDER extends ParameterBinder> extends ParameterBinderProvider<K>, PreparedStatementWriterIndex<K, BINDER> {
	
	/**
	 * @return all available keys
	 */
	Set<K> keys();
	
	/**
	 * Aims at being used for iterating over all keys and values instead of calling {@link #getBinder(Object)} for each element of {@link #keys()}
	 * @return all the key + value pairs of this index
	 */
	Set<Entry<K, BINDER>> all();
	
	/**
	 * Short way of getting a {@link ParameterBinderIndex} from a Map
	 * @param parameterBinders the source of {@link ParameterBinder}
	 * @return a {@link ParameterBinderIndex} backed by the Map
	 */
	static <K, BINDER extends ParameterBinder> ParameterBinderIndex<K, BINDER> fromMap(Map<K, BINDER> parameterBinders) {
		return new ParameterBinderIndexFromMap<>(parameterBinders);
	}
	
	/**
	 * A simple {@link ParameterBinderIndex} that takes its values from a {@link Map}
	 * 
	 * @author Guillaume Mary
	 */
	class ParameterBinderIndexFromMap<ParamType, BINDER extends ParameterBinder> extends ParameterBinderProviderFromMap<ParamType, BINDER> implements ParameterBinderIndex<ParamType, BINDER> {
		
		public ParameterBinderIndexFromMap(Map<ParamType, BINDER> parameterBinders) {
			super(parameterBinders);
		}
		
		@Override
		public Set<ParamType> keys() {
			return getParameterBinders().keySet();
		}
		
		@Override
		public Set<Entry<ParamType, BINDER>> all() {
			return getParameterBinders().entrySet();
		}
	}
}
